/**
 * @p.md
 * 
 * MongoDBProvider 是一个基于 MongoDB 数据库的持久化提供者
 * 
 * 注意：使用此提供者需要安装 mongodb 依赖:
 * ```
 * npm install mongodb
 * ```
 */
import { MongoClient, Db, Collection } from 'mongodb';
import { PersistenceProvider } from './persistenceProvider';

/**
 * MongoDB 存储项接口
 */
interface MongoStorageItem {
  persistenceId: string;
  index: number;
  data: any;
  timestamp: number;
}

/**
 * MongoDB 持久化提供者，用于将事件和快照持久化到 MongoDB 数据库
 */
export class MongoDBProvider implements PersistenceProvider {
  private client: MongoClient;
  private db?: Db;
  private eventsCollection?: Collection<MongoStorageItem>;
  private snapshotsCollection?: Collection<MongoStorageItem>;
  private isConnected: boolean = false;
  
  /**
   * 构造函数
   * @param connectionString MongoDB 连接字符串，默认为 'mongodb://localhost:27017'
   * @param dbName 数据库名称，默认为 'protoactor'
   */
  constructor(
    private readonly connectionString: string = 'mongodb://localhost:27017',
    private readonly dbName: string = 'protoactor'
  ) {
    this.client = new MongoClient(connectionString);
    this.connect();
  }
  
  /**
   * 连接到 MongoDB 数据库
   */
  private async connect(): Promise<void> {
    if (this.isConnected) return;
    
    try {
      await this.client.connect();
      this.db = this.client.db(this.dbName);
      
      // 获取集合
      this.eventsCollection = this.db.collection<MongoStorageItem>('events');
      this.snapshotsCollection = this.db.collection<MongoStorageItem>('snapshots');
      
      // 创建索引
      await this.eventsCollection.createIndex({ persistenceId: 1, index: 1 }, { unique: true });
      await this.snapshotsCollection.createIndex({ persistenceId: 1, index: 1 }, { unique: true });
      
      this.isConnected = true;
      console.log(`已连接到 MongoDB: ${this.connectionString}, 数据库: ${this.dbName}`);
    } catch (error) {
      console.error('MongoDB 连接错误:', error);
      throw error;
    }
  }
  
  /**
   * 关闭数据库连接
   */
  public async close(): Promise<void> {
    if (this.isConnected) {
      await this.client.close();
      this.isConnected = false;
      console.log('MongoDB 连接已关闭');
    }
  }
  
  /**
   * 获取指定持久化 ID 的事件
   * @param persistenceId 持久化 ID
   * @param fromIndex 开始索引（包含）
   * @param toIndex 结束索引（包含）
   * @returns 事件数组
   */
  async getEventsByPersistenceId(persistenceId: string, fromIndex: number, toIndex: number): Promise<any[]> {
    await this.ensureConnected();
    
    const items = await this.eventsCollection!.find({
      persistenceId,
      index: { $gte: fromIndex, $lte: toIndex }
    }).sort({ index: 1 }).toArray();
    
    return items.map(item => item.data);
  }
  
  /**
   * 获取指定持久化 ID 的最新快照
   * @param persistenceId 持久化 ID
   * @returns 快照数据，如果不存在则返回 null
   */
  async getSnapshotByPersistenceId(persistenceId: string): Promise<any | null> {
    await this.ensureConnected();
    
    const item: MongoStorageItem | null = await this.snapshotsCollection!.findOne(
      { persistenceId },
      { sort: { index: -1 } }
    );
    
    return item ? item.data : null;
  }
  
  /**
   * 持久化事件
   * @param persistenceId 持久化 ID
   * @param eventIndex 事件索引
   * @param event 事件数据
   */
  async persistEvent(persistenceId: string, eventIndex: number, event: any): Promise<void> {
    await this.ensureConnected();
    
    const storageItem: MongoStorageItem = {
      persistenceId,
      index: eventIndex,
      data: event,
      timestamp: Date.now()
    };
    
    await this.eventsCollection!.updateOne(
      { persistenceId, index: eventIndex },
      { $set: storageItem },
      { upsert: true }
    );
  }
  
  /**
   * 持久化快照
   * @param persistenceId 持久化 ID
   * @param snapshotIndex 快照索引
   * @param snapshot 快照数据
   */
  async persistSnapshot(persistenceId: string, snapshotIndex: number, snapshot: any): Promise<void> {
    await this.ensureConnected();
    
    const storageItem: MongoStorageItem = {
      persistenceId,
      index: snapshotIndex,
      data: snapshot,
      timestamp: Date.now()
    };
    
    await this.snapshotsCollection!.updateOne(
      { persistenceId, index: snapshotIndex },
      { $set: storageItem },
      { upsert: true }
    );
  }
  
  /**
   * 删除事件
   * @param persistenceId 持久化 ID
   * @param fromIndex 开始索引（包含）
   * @param toIndex 结束索引（包含）
   */
  async deleteEvents(persistenceId: string, fromIndex: number, toIndex: number): Promise<void> {
    await this.ensureConnected();
    
    await this.eventsCollection!.deleteMany({
      persistenceId,
      index: { $gte: fromIndex, $lte: toIndex }
    });
  }
  
  /**
   * 删除快照
   * @param persistenceId 持久化 ID
   * @param fromIndex 开始索引（包含）
   * @param toIndex 结束索引（包含）
   */
  async deleteSnapshots(persistenceId: string, fromIndex: number, toIndex: number): Promise<void> {
    await this.ensureConnected();
    
    await this.snapshotsCollection!.deleteMany({
      persistenceId,
      index: { $gte: fromIndex, $lte: toIndex }
    });
  }
  
  /**
   * 确保已连接到数据库
   */
  private async ensureConnected(): Promise<void> {
    if (!this.isConnected) {
      await this.connect();
    }
  }
} 